package com.horizon.im.imServer.serverHandler;

import com.horizon.im.common.bean.msg.ProtoMsg;
import com.horizon.im.imServer.distributed.ImWorker;
import com.horizon.util.JsonUtil;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;

@Slf4j
@ChannelHandler.Sharable
public class ImNodeHeartBeatClientHandler extends ChannelInboundHandlerAdapter {
    String from = null;
    int seq = 0;

    //发送心跳的时间间隔，单位秒
    private static final int HEARTBEAT_INTERVAL = 50;

    public ProtoMsg.Message buildMessageHeartBeat() {
        if (null == from) {
            from = JsonUtil.pojoToJson(ImWorker.getInstance().getLocalNode());
        }

        ProtoMsg.Message.Builder mb = ProtoMsg.Message.newBuilder()
                .setType(ProtoMsg.HeadType.HEART_BEAT)
                .setSequence(++seq);
        ProtoMsg.MessageHeartBeat.Builder heartBeat =
                ProtoMsg.MessageHeartBeat.newBuilder()
                .setSeq(seq).setJson(from).setUid("-1");
        return mb.setHeartBeat(heartBeat).build();
    }

    //服务器端心跳回写
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        //判断消息实体
        if (null == msg|| !(msg instanceof  ProtoMsg.Message)) {
            super.channelRead(ctx, msg);
            return;
        }

        //判断类型
        ProtoMsg.Message pkg = (ProtoMsg.Message) msg;
        ProtoMsg.HeadType headType = pkg.getType();
        if (headType.equals(ProtoMsg.HeadType.HEART_BEAT)) {
            ProtoMsg.MessageHeartBeat messageHeartBeat = pkg.getHeartBeat();
            log.info(" 收到imNode heart_beat 消息 from "+ messageHeartBeat.getJson());
            log.info(" 收到imNode Heart_beat seq " + messageHeartBeat.getSeq());
        }else {
            super.channelRead(ctx, msg);
        }
    }

    //在被加入pipleLine时，开始发送心跳
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        heartBeat(ctx);
    }

    //使用定时器发送心跳
    public void heartBeat(ChannelHandlerContext ctx) {
        ProtoMsg.Message message = buildMessageHeartBeat();
        ctx.executor().schedule(()->{
            if (ctx.channel().isActive()){
                log.info("发送imnode heart-beat消息");
                ctx.writeAndFlush(message);
                //继续调用，发送下一次心跳
                heartBeat(ctx);
            }
        }, HEARTBEAT_INTERVAL, TimeUnit.SECONDS);
    }
}
